package com.dmjy.boot.common.enums;

import java.util.Arrays;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * 枚举接口
 *
 * @author 敖癸
 * @formatter:on
 * @since 2022/6/17
 */
public interface IEnum<V> {

    /**
     * 枚举value
     *
     * @return V
     * @author 敖癸
     * @since 2023/2/9 - 20:59
     */
    V value();

    /**
     * 获取枚举说明
     *
     * @return java.lang.String
     * @author 敖癸
     * @since 2023/2/9 - 20:59
     */
    String description();


    /**
     * 通过value查找enum实例
     *
     * @param enumClass 枚举类
     * @param value value
     * @return E
     * @author 敖癸
     * @since 2023/11/30 - 0:21
     */
    static <V, E extends Enum<E> & IEnum<V>> E instance(Class<E> enumClass, V value) {
        IEnum.assertIsEnum(enumClass);
        return Objects.nonNull(value) ? Arrays.stream(enumClass.getEnumConstants())
                .filter((var) -> var.value().equals(value))
                .findAny()
                .orElseThrow(() -> new EnumConstantNotPresentException(enumClass, "未找到[" + value + "]对应的枚举")) : null;
    }

    /**
     * 通过value查找enum实例, 未找到不抛异常, 由调用者自行处理
     *
     * @param enumClass 枚举类
     * @param value value
     * @return java.util.Optional<E>
     * @author 敖癸
     * @since 2023/11/30 - 0:23
     */
    static <V, E extends Enum<E> & IEnum<V>> Optional<E> instanceOpt(Class<E> enumClass, V value) {
        IEnum.assertIsEnum(enumClass);
        return Objects.nonNull(value) ? Arrays.stream(enumClass.getEnumConstants())
                .filter((var) -> var.value().equals(value))
                .findAny() : Optional.empty();
    }

    /**
     * 判断value是否有对应的枚举实例
     *
     * @param enumClass 枚举类
     * @param value value
     * @return boolean
     * @author 敖癸
     * @since 2023/11/30 - 0:20
     */
    static <V, E extends Enum<E> & IEnum<V>> boolean isMatch(Class<E> enumClass, V value) {
        IEnum.assertIsEnum(enumClass);
        return Arrays.stream(enumClass.getEnumConstants()).anyMatch((var) -> var.value().equals(value));
    }

    /**
     * 将枚举转换成 map结构, value为key, description为value
     *
     * @param enumClass 枚举类
     * @return Map<V, String>
     * @author 敖癸
     * @since 2023/11/30 - 0:24
     */
    static <V, E extends IEnum<V>> Map<V, String> toMap(Class<E> enumClass) {
        IEnum.assertIsEnum(enumClass);
        return Arrays.stream(enumClass.getEnumConstants()).collect(Collectors.toMap(IEnum::value, IEnum::description));
    }

    /**
     * 通过value来获取枚举的description属性
     *
     * @param enumClass 枚举类
     * @param value value
     * @return java.lang.String
     * @author 敖癸
     * @since 2023/11/30 - 0:28
     */
    static <V, E extends IEnum<V>> Optional<String> description(Class<E> enumClass, V value) {
        IEnum.assertIsEnum(enumClass);
        return Arrays.stream(enumClass.getEnumConstants())
                .filter((var) -> var.value().equals(value))
                .map(IEnum::description)
                .findAny();
    }

    /**
     * 检查类型是否是IEnum实现枚举类
     *
     * @param clazz 枚举类
     * @author 敖癸
     * @since 2022/6/17 - 15:11
     */
    static <E> void assertIsEnum(Class<E> clazz) {
        boolean isEnumInstance = clazz.isEnum() && IEnum.class.isAssignableFrom(clazz);
        if (!isEnumInstance) {
            throw new IllegalArgumentException("enum check exception!");
        }
    }

}
